package com.emmmya.ocs.modules.system.file.serviceimpl;

import com.emmmya.ocs.modules.system.file.service.DirectoryService;
import com.emmmya.ocs.modules.system.file.service.FileService;
import com.emmmya.ocs.modules.system.setting.entity.FileProperties;
import com.emmmya.ocs.common.base.BaseDao;
import com.emmmya.ocs.config.WebServerConfig;
import com.emmmya.ocs.modules.system.file.dao.FileDao;
import com.emmmya.ocs.modules.system.file.dao.mapper.FileMapper;
import com.emmmya.ocs.modules.system.file.entity.File;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartFile;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.nio.file.*;
import java.util.List;

@Slf4j
@Service
@Transactional
public class FileServiceImpl implements FileService {
  @Autowired
  FileDao fileDao;
  @Autowired
  FileMapper fileMapper;

  //文件夹管理service
  @Autowired
  DirectoryService directoryService;

  //框架自带的文件上传表

  //获取应用上下文工具
  @Autowired
  WebServerConfig webServerConfig;

  private final Path fileStorageLocation; // 文件在本地存储的地址

  @Autowired
  public FileServiceImpl(FileProperties fileProperties) {
    this.fileStorageLocation = Paths.get(fileProperties.getUploadDir()).toAbsolutePath().normalize();
    try {
      Files.createDirectories(this.fileStorageLocation);
    } catch (Exception ex) {
      throw new RuntimeException("无法创建将存储上载文件的目录。", ex);
    }
  }

  /**
   * 存储文件到系统
   *
   * @param file 文件
   * @return 文件名
   */
  @Override
  public File storeFile(MultipartFile file,String fKey,Long dirId) {
    // 拿到文件名
    String fileName = fKey;

    try {
      // 检查文件名是否包含无效字符
      if(fileName.contains("..")) {
        throw new RuntimeException("对不起的！文件名包含无效的路径序列 " + fileName);
      }

      // 将文件复制到目标位置（用相同名称替换现有文件）
      Path targetLocation = this.fileStorageLocation.resolve(fileName);
      //保存到服务器
      Files.copy(file.getInputStream(), targetLocation, StandardCopyOption.REPLACE_EXISTING);
      //生成框架的File实体
      File f = new File();
      //拼接uri
      String url = null;
      //通过项目的上下文对象，
      url = "/assets/getFile/"+fileName;

      //设置File的参数
      f.setFileName(file.getOriginalFilename());
      f.setFileSize(file.getSize());
      f.setFileType(file.getContentType());
      f.setFkey(fKey);
      f.setFilePath(targetLocation.toAbsolutePath().toString());
      f.setUrl(url);
      f.setFileSize(file.getSize());
      f.setDirId(dirId);
      //f.setFKey(file.getOriginalFilename());
      File save = fileDao.save(f);
      return save;
    } catch (IOException ex) {
      throw new RuntimeException("无法存储文件" + fileName + ". 请重试!", ex);
    }finally {
      //清除缓存
      directoryService.clearCache(dirId);
    }
  }




  @Override
  public void deleteAll(Long id) {
    File file = get(id);
    String fileLName = file.getFkey();
    Long dirId = file.getDirId();
    Path normalize = this.fileStorageLocation.resolve(fileLName).normalize();
    try {
      Files.delete(normalize);
      delete(id);
    } catch (Exception e){
      //e.printStackTrace();
      throw new RuntimeException("删除出错了");
    }finally {
      //清除缓存
      directoryService.clearCache(dirId);
    }
  }

  /**
   * 给系统文件生成文件管理模块信息
   * @param filePath  文件路径
   */
  @Override
  public File infoFile(String fileName, String filePath,Long dirId) throws Exception {
    try {
      Resource resource = loadFileAsResource(filePath);
      String fileKeys = resource.getFilename();
      MultipartFile file = getMultipartFile(resource.getFile());

      // 检查文件名是否包含无效字符
      if (fileKeys.contains("..")) {
        throw new RuntimeException("对不起的！文件名包含无效的路径序列 " + fileName);
      }

//      // 将文件复制到目标位置（用相同名称替换现有文件）
//      Path targetLocation = this.fileStorageLocation.resolve(fileName);
//      //保存到服务器
//      Files.copy(file.getInputStream(), targetLocation, StandardCopyOption.REPLACE_EXISTING);
//
//      Files.delete(resource.getFile().toPath());

      //生成框架的File实体
      File f = new File();
      //拼接uri
      String url = null;
      //通过项目的上下文对象，获取端口号。
      url = "/assets/getFile/"+fileKeys;
//      if (webServerConfig != null) {
//        WebServerApplicationContext appContext = webServerConfig.getAppContext();
//        int port = appContext.getWebServer().getPort();
//        url = ServletUriComponentsBuilder.fromCurrentContextPath().port(port)
//                .path("/assets/getFile/").path(fileKeys).toUriString();
//      } else {
//        url = ServletUriComponentsBuilder.fromCurrentContextPath()
//                .path("/assets/getFile/").path(fileKeys).toUriString();
//      }

      //设置File的参数
      f.setFileName(fileName);
      f.setFileSize(file.getSize());
      f.setFileType(file.getContentType());
      f.setFkey(fileKeys);
      f.setFilePath(resource.getFile().getAbsolutePath());
      f.setUrl(url);
      f.setFileSize(file.getSize());
      f.setDirId(dirId);
      //f.setFKey(file.getOriginalFilename());
      File save = fileDao.save(f);
      return save;
    }catch (Exception e){
      e.printStackTrace();
    }finally {
      //清除缓存
      directoryService.clearCache(dirId);
    }
    return null;
  }

  /**
   * 加载文件
   * @param fileName 文件名
   * @return 文件
   */
  @Override
  public Resource loadFileAsResource(String fileName) {
    try {
      Path filePath = this.fileStorageLocation.resolve(fileName).normalize();
      Resource resource = new UrlResource(filePath.toUri());
      if(resource.exists()) {
        return resource;
      } else {
//        String fileKeys = fileName.substring(0,fileName.lastIndexOf("."));
        File itemFile = fileDao.findByFkey(fileName);
        if(itemFile != null) {
          log.warn(itemFile.getFilePath());
          Path sopPath = Paths.get(itemFile.getFilePath()).toAbsolutePath().normalize();
          resource = new UrlResource(sopPath.toUri());
          if (resource.exists()) {
            return resource;
          }
        } else{
          log.warn("未查询到 \'"+fileName+"\' 的文件");
        }
        throw new RuntimeException("未查询到文件名为：" + fileName +" 的文件");
      }
    } catch (MalformedURLException ex) {
      throw new RuntimeException("文件未找到" + fileName, ex);
    }
  }

  @Override
  public File findByFKey(String fKey) {
    return fileDao.findByFkey(fKey);
  }

  @Override
  public List<File> getAllFileList() {
    return fileDao.findAll();
  }

//  @Override
//  public Boolean createDir(File file) {
//    //return fileDao.createDir(file);
//    try{
//      fileMapper.createDir(file);
//      return true;
//    }catch (Exception e){
//      e.printStackTrace();
//      return false;
//    }
//  }

  @Override
  public List<File> findByDirId(Long dirId) {
    return fileDao.findByDirId(dirId);
  }

  @Override
  public BaseDao<File, Long> getRepository() {
    return fileDao;
  }


  /**
   * 获取封装得MultipartFile
   * @return MultipartFile
   */

  public static MultipartFile getMultipartFile(java.io.File file) {
    FileItem item = new DiskFileItemFactory().createItem("file"
            , MediaType.MULTIPART_FORM_DATA_VALUE
            , true
            , file.getName());
    try (InputStream input = new FileInputStream(file);
         OutputStream os = item.getOutputStream()) {
      // 流转移
      IOUtils.copy(input, os);
    } catch (Exception e) {
      throw new IllegalArgumentException("Invalid file: " + e, e);
    }

    return new CommonsMultipartFile(item);
  }

}